#pragma once

#include "Common.hpp"
#include <unistd.h>

namespace SocketModule
{
    const int Gbacklog = 8;
    const int defaultfd = -1;

    class Socket
    {
    public:
        ~Socket() {}
        virtual void CreateSocket() = 0;
        virtual void BindSocket(uint16_t port) = 0;
        virtual void ListenSocket(int backlog) = 0;
        // virtual std::shared_ptr<Socket> AcceptSocket(InetAddr *client) = 0;
        virtual int AcceptSocket(InetAddr *client) = 0;

        virtual void Close() = 0;
        virtual int getFD() = 0;
        virtual int Recv(std::string *message) = 0;
        virtual int Send(std::string &message) = 0;
        virtual int Connect(std::string serveip, uint16_t serveport) = 0;

    public:
        void BuildTCPSocketfd(uint16_t port, int backlog = Gbacklog)
        {
            CreateSocket();
            BindSocket(port);
            ListenSocket(backlog);
        }
        void BuildTCPClientSockfd()
        {
            CreateSocket();
        }
    };

    class TCPSocket : public Socket
    {
    public:
        TCPSocket() : _sockfd(defaultfd) {}
        TCPSocket(int sockfd) : _sockfd(sockfd)
        {
        }
        void CreateSocket() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(FATAL) << "create socket error";
                exit(SOCKET_ERR);
            }
            LOG(INFO) << "create socket success";
        }
        void BindSocket(uint16_t port) override
        {
            InetAddr local(port);
            int n = ::bind(_sockfd, local.CompulsoryNetAddr(), local.AddrLen());
            if (n < 0)
            {
                LOG(FATAL) << "bind error";
                exit(BIND_ERR);
            }
            LOG(INFO) << "bind success";
        }
        void ListenSocket(int backlog = Gbacklog) override
        {
            int n = ::listen(_sockfd, backlog);
            if (n < 0)
            {
                LOG(FATAL) << "listen error";
                exit(LISTEN_ERR);
            }
            LOG(INFO) << "listen success";
        }
        // std::shared_ptr<Socket> AcceptSocket(InetAddr *client) override
        int AcceptSocket(InetAddr *client)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int fd = ::accept(_sockfd, (sockaddr *)&peer, &len);
            if (fd < 0)
            {
                LOG(WARNING) << "accept unsuccess";
                // return nullptr;
                return -1;
            }
            // LOG(INFO)<<"accpet success";
            // client->SetAddr(peer);
            // return std::make_shared<TCPSocket>(fd);
            return fd;
        }

        void Close() override
        {
            if (_sockfd >= 0)
                ::close(_sockfd);
        }
        // 参数设置为引用和指针都可以，
        // 网络编程中，如果涉及到缓冲区的操作，参数应该尽可能使用指针或者引用
        int Recv(std::string *message) override
        {
            char buffer[4096 * 3]; // 一会改大一点试试，应该不是这里的问题，还是不能连接
            // 两种读取方式是等价的
            size_t n = ::read(_sockfd, buffer, sizeof buffer - 1);
            // size_t n=::recv(_sockfd,buffer,sizeof buffer - 1,0);
            if (n > 0)
            {
                buffer[n] = 0;
                // 处理读取的报文不完整，拼接在原来的后面，可以接着读，直到完整的报文
                *message += buffer;
            }
            return n;
        }

        int Send(std::string &message) override
        {
            return send(_sockfd, message.c_str(), message.size(), 0);
        }
        int Connect(std::string serveip, uint16_t serveport) override
        {
            InetAddr serve(serveip, serveport);
            return ::connect(_sockfd, serve.CompulsoryNetAddr(), serve.AddrLen());
        }
        int getFD()
        {
            return _sockfd;
        }

    private:
        int _sockfd;
    };
}